package com.mrd.gtimpframe.service.impl;

import com.github.pagehelper.PageInfo;
import com.mrd.base.Jqgrid;
import com.mrd.framework.config.web.json.Result;
import com.mrd.framework.ui.filter.SearchRule;
import com.mrd.framework.ui.filter.SearchRuleOption;
import com.mrd.gtimp.base.entity.Role;
import com.mrd.gtimp.base.entity.User;
import com.mrd.gtimpframe.entity.Notice;
import com.mrd.gtimpframe.entity.ReceivedNotice;
import com.mrd.gtimpframe.repository.NoticeMapper;
import com.mrd.gtimpframe.service.NoticeService;
import com.mrd.gtimpframe.strategy.NoticeRoleMatcher;
import com.mrd.util.FileUtil;
import com.mrd.util.JsonBinder;
import com.mrd.util.LoginUtil;
import com.mrd.util.ResponseUtils;

import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.domain.PageImpl;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;

/**
 * Created by dusy on 2017/11/29.
 */
@Service("noticeServiceImpl")
public class NoticeServiceImpl implements NoticeService {
    @Resource
    private NoticeMapper noticeMapper;
    @Value("${notice.picture.path}")
    private String picturePath;
    @Value("${notice.picture.path.temp}")
    private String pictureTempPath;
    @Value("${notice.picture.maxSize}")
    private long maxSize;
    @Value("${notice.picture.maxNumber}")
    private long maxNumber;

    @Override
    public int deleteByPrimaryKey(Object id) {
        return noticeMapper.deleteByPrimaryKey((String) id);
    }

    @Override
    public int insert(Notice notice) {
        return noticeMapper.insert(notice);
    }

    @Override
    public int insertSelective(Notice notice) {
        return noticeMapper.insertSelective(notice);
    }

    @Override
    public Notice selectByPrimaryKey(Object id) {
        return noticeMapper.selectByPrimaryKey((String) id);
    }

    @Override
    public int updateByPrimaryKeySelective(Notice notice) {
        return noticeMapper.updateByPrimaryKeySelective(notice);
    }

    @Override
    public int updateByPrimaryKey(Notice notice) {
        return noticeMapper.updateByPrimaryKey(notice);
    }

    @Override
    public String[][] getAppliedRoles() {
        return new String[][]{
                {"全部", NoticeRoleMatcher.NoticeRole.ALL.name()},
                {"客户", NoticeRoleMatcher.NoticeRole.CUSTOMER.name()},
                {"报关行", NoticeRoleMatcher.NoticeRole.SUPPLIER.name()}
        };
    }

    /**
     * 获取发布中的公告
     */
    @Override
    public List<Notice> getPublishing(String newPublish) {
        return noticeMapper.selectPublishingNotices(newPublish);
    }

    /**
     * 发布公告
     */
    @Override
    public Result noticePublish(String noticeId) {
        String userId = LoginUtil.getLoginUserId();
        Notice notice = this.selectByPrimaryKey(noticeId);
        if (notice == null) {
            return Result.newFailInstance("无法获取该公告信息");
        }
        if (StringUtils.isEmpty(notice.getAppliedRoles())) {
            return Result.newFailInstance("请先设置适用角色");
        }
        String appliedRole = notice.getAppliedRoles();
        List<Notice> publishingList = noticeMapper.selectPublishingNotices("0");
        List<Notice> modifyList = new ArrayList<>();
        //发布新公告
        notice.setNewPublishRoles(notice.getAppliedRoles());
        notice.setModifier(userId);
        notice.setModifyTime(new Date());
        notice.setState("1");//生效
        notice.setNewPublish("0");//最新发布
        //批量更新
        modifyList.add(notice);
        if(NoticeRoleMatcher.NoticeRole.ALL.name().equals(appliedRole)){
            for (Notice publishingNotice : publishingList) {
                publishingNotice.setNewPublish("1");
                publishingNotice.setModifyTime(new Date());
                publishingNotice.setModifier(userId);
                modifyList.add(publishingNotice);
            }
        }
        int i = noticeMapper.updateBatch(modifyList);
        if (i > 0) {
            return Result.newSuccessInstance("已成功发布");
        } else {
            return Result.newFailInstance("发布失败");
        }
    }

    /**
     * 图片上传、替换
     */
    @Override
    public Result uploadOrReplace(String noticeId, String noticeType, String replacePicture, MultipartFile picture) {
        String saveFilePath = getNoticeTempDir(noticeId) + File.separator;//保存后的文件路径
        File[] uploadFile = new File(saveFilePath).listFiles();
        if (uploadFile != null && uploadFile.length >= maxNumber) {
            return Result.newFailInstance("上传图片不能超过" + maxNumber + "张");
        }
        if (picture.getSize() > maxSize * 1024) {
            return Result.newFailInstance("图片不能超过" + new DecimalFormat("######0.00").format(maxSize / 1024d) + "M");
        }
        //处理要替换的文件
        File tempFile = null;
        File replaceFile = null;
        String fileName = picture.getOriginalFilename();//图片名
        if (StringUtils.isNotEmpty(replacePicture)) {
            tempFile = new File(saveFilePath + replacePicture + ".replace");
            replaceFile = new File(saveFilePath + replacePicture);
            if (replaceFile.exists()) {
                try {
                    FileUtils.moveFile(replaceFile, tempFile);
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        //保存文件
        try {
            File file = new File(saveFilePath + fileName);
            FileUtils.copyToFile(picture.getInputStream(), file);
            if (tempFile != null && tempFile.exists()) {//保存新图片后删除要替换的文件
                FileUtils.deleteQuietly(tempFile);
            }
        } catch (IOException e) {
            e.printStackTrace();
            return Result.newFailInstance(e.getMessage());
        } finally {
            if (tempFile != null && tempFile.exists()) {//上传文件保存失败，回复要替换的文件
                try {
                    FileUtils.moveFile(tempFile, replaceFile);
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        String tempPath = "/notice/picture/" + noticeId + "?fileName=" + fileName + "&temp=12446234";
        Map<String, String> map = new HashMap<>();//返回参数：上传图片的访问路径及图片名称
        map.put("path", tempPath);
        map.put("fileName", fileName);
        return Result.newSuccessInstance("上传完成", map);
    }

    /**
     * 将配置中需要替换的字符进行替换
     */
    private String parsePath(String path) {
        if (path != null) {
            Pattern pattern = Pattern.compile("\\$\\{.+}");
            Matcher matcher = pattern.matcher(path);
            while (matcher.find()) {
                String tag = matcher.group().replace("${", "").replace("}", "");
                path = path.replace(matcher.group(), System.getProperty(tag));
            }
            path = path.replace("/", File.separator).replace("\\", File.separator);
        }
        return path;
    }

    /**
     * 获取公告图片
     *
     * @param temp     非空表示从临时文件夹获取图片
     * @param noticeId 公告id
     * @param fileName 要读取的图片名
     */
    @Override
    public void getPicture(HttpServletResponse response, String temp, String noticeId, String fileName) {
        String path;//图片真实路径
        if (StringUtils.isEmpty(temp)) {
            path = getNoticeDir(noticeId) + fileName;
        } else {
            path = getNoticeTempDir(noticeId) + fileName;
        }
        InputStream inputStream = null;
        BufferedOutputStream bufferedOutputStream = null;
        try {
            inputStream = new FileInputStream(new File(path));
            bufferedOutputStream = new BufferedOutputStream(response.getOutputStream());
            byte b[] = new byte[1024];
            int len = inputStream.read(b);
            while (len > 0) {
                bufferedOutputStream.write(b, 0, len);
                len = inputStream.read(b);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (inputStream != null) {
                    inputStream.close();
                }
                if (null != bufferedOutputStream) {
                    bufferedOutputStream.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 获取公告列表
     */
    @Override
    public void getNoticeList(HttpServletResponse response, Jqgrid jqgrid, String edit) {
        List<String> roles = null;
        if (StringUtils.isEmpty(edit)) {//公告列表只取生效的公告
            jqgrid.addRule(new SearchRule("STATE", SearchRuleOption.eq, "1"));
            List<Role> roleList = LoginUtil.getLoginUser().getRoles();
            roles = roleList.stream().map(role -> role.getId()).collect(Collectors.toList());
        } else {//排除逻辑删除的数据
            jqgrid.addRule(new SearchRule("STATE", SearchRuleOption.ne, "2"));
        }
        jqgrid.pageWithMybatis();
        boolean defaultSort = true;//使用默认排序
        if (jqgrid.getOrder() != null) {
            jqgrid.sortWithMybatis();
            defaultSort = false;
        }
        String whereCase = jqgrid.getWhereCase();
        List<Notice> noticeList = noticeMapper.selectByWhereCase(whereCase, defaultSort, roles);
        String[][] appliedRoles = this.getAppliedRoles();
        Map<String, String> roleMap = new HashMap<>();
        for (String[] role : appliedRoles) {
            roleMap.put(role[1], role[0]);
        }
        if (StringUtils.isNotEmpty(edit)) {//将适用角色转换为中文
            noticeList.forEach(notice -> {
                notice.setAppliedRoles(roleMap.get(notice.getAppliedRoles()));
            });
        } else {//根据用户角色修正公告的最新发布状态
            noticeList.forEach(notice -> {
                if ("0".equals(notice.getNewPublish())) {
                    boolean containRole = false;
                    for (Role role : LoginUtil.getLoginUser().getRoles()) {
                        if (notice.getNewPublishRoles().contains(role.getId())) {
                            containRole = true;
                            break;
                        }
                    }
                    if (!containRole) {
                        notice.setNewPublish("1");
                    }
                }
            });
        }
        PageInfo<Notice> pageInfo = new PageInfo<>(noticeList);
        JsonBinder jsonBinder = JsonBinder.buildNonNullBinder();
        jsonBinder.setDateFormat("yyyy-MM-dd HH:mm");
        ResponseUtils.renderJson(response, jsonBinder.toJson(new PageImpl(noticeList, jqgrid.getPage(), pageInfo.getTotal())));
    }

    /**
     * 展示最新公告
     */
    @Override
    public Result showNewNotice() {
        User user = LoginUtil.getLoginUser();
        //获取用户未看过的新公告
        List<Notice> noticeList = noticeMapper.selectNewNoticeByUserId(user.getId());
        if (noticeList != null && noticeList.size() > 0) {
            StringBuffer noticeIds = new StringBuffer();
            List<String> roleIds = user.getRoles().stream().map(Role::getId).collect(Collectors.toList());
            List<String> pictureList = new ArrayList<>();//所有公告图片
            List<Notice> publicToAll = new ArrayList<>();//推向全部用户的公告
            for (Notice notice : noticeList) {
                String newPublishRoles = notice.getNewPublishRoles();
                if(newPublishRoles == null){
                    continue;
                }
                if (NoticeRoleMatcher.NoticeRole.ALL.name().equals(newPublishRoles)) {
                    publicToAll.add(notice);
                    continue;
                }
                if (NoticeRoleMatcher.doMatch(newPublishRoles, roleIds)) {
                    pictureList.addAll(notice.getPictureList());
                    noticeIds.append(",").append(notice.getId());
                    break;
                }
            }

            if(noticeIds.length() == 0){
                for (Notice notice : publicToAll) {
                    pictureList.addAll(notice.getPictureList());
                    noticeIds.append(",").append(notice.getId());
                }
            }

            if (noticeIds.length() > 1) {
                noticeIds.deleteCharAt(0);
            }
            if (pictureList.size() > 0) {
                //去除重复图片
                List<String> repetition = new ArrayList<>();
                Iterator it = pictureList.iterator();
                while (it.hasNext()) {
                    String picture = (String) it.next();
                    String pictureMD5 = picture.substring(picture.lastIndexOf("=") + 1);
                    if (repetition.contains(pictureMD5)) {
                        it.remove();
                    } else {
                        repetition.add(pictureMD5);
                    }
                }
                Map<String, Object> map = new HashMap<String, Object>();
                map.put("noticeIds", noticeIds);
                map.put("pictureList", pictureList);
                return Result.newSuccessInstance("有新公告", map);
            }
        }
        return Result.newFailInstance("所有公告都已看过了");
    }

    /**
     * 标记用户已看了公告
     */
    @Override
    public Result haveReceivedNotice(String ids) {
        if (ids == null) {
            return Result.newFailInstance("参数缺失");
        }
        List<ReceivedNotice> receivedNotices = new ArrayList<>();
        for (String noticeId : ids.split(",")) {
            receivedNotices.add(new ReceivedNotice(noticeId, LoginUtil.getLoginUserId()));
        }
        int i = noticeMapper.insertReceivedNotice(receivedNotices);
        if (i > 0) {
            return Result.newSuccessInstance("标记完成");
        }
        return Result.newFailInstance("标记失败");
    }

    /**
     * 打开编辑页面时的预备处理
     */
    @Override
    public Result dealBeforeEdit(String noticeId) {
        try {
            File tempDir = new File(getNoticeTempDir());
            if (tempDir.exists()) {//先清空一次
                FileUtils.cleanDirectory(tempDir);
            }
            //新增先预先定一个id
            if (noticeId == null) {
                return Result.newSuccessInstance("获取id", UUID.randomUUID().toString().replace("-", ""));
            }
            // 将原图片复制到临时文件夹以备修改
            Notice notice = this.selectByPrimaryKey(noticeId);
            if (notice != null && StringUtils.isNotEmpty(notice.getPictures())) {
                File dir = new File(getNoticeDir(noticeId));
                if (dir.exists()) {
                    FileUtils.copyDirectoryToDirectory(dir, tempDir);
                }
            }
            return Result.newSuccessInstance("处理完毕");
        } catch (IOException e) {
            e.printStackTrace();
            return Result.newFailInstance("未能成功处理" + e.getMessage());
        }
    }

    /**
     * 提交公告
     */
    @Override
    public Result submit(Notice notice) {
        //将临时文件夹覆盖原文件
        Notice oldNotice = this.selectByPrimaryKey(notice.getId());
        String pictures = notice.getPictures();
        if (StringUtils.isNotEmpty(pictures) && (oldNotice == null || !pictures.equals(oldNotice.getPictures()))) {
            String[] newPictures = pictures.split(",");
            if (newPictures.length > maxNumber) {
                return Result.newFailInstance("上传图片不能超过" + maxNumber + "张");
            }
            StringBuffer pictureSbf = new StringBuffer();
            for (String picture : newPictures) {
                //文件以文件的MD5值重命名，方便去重
                if (StringUtils.isNotEmpty(picture)) {
                    File file = new File(getNoticeTempDir(notice.getId()) + picture);
                    if (!file.exists()) {
                        return Result.newFailInstance("图片没有上传");
                    }
                    String newName = FileUtil.getMD5(file) + file.getName().substring(file.getName().lastIndexOf("."));
                    File newFile = new File(getNoticeDir(notice.getId()) + newName);
                    try {//转移到正式目录
                        FileUtils.copyFile(file, newFile);
                    } catch (IOException e) {
                        e.printStackTrace();
                        return Result.newFailInstance("图片" + picture + "处理出错");
                    }
                    pictureSbf.append("," + newName);
                }
            }
            if (pictureSbf.length() > 1) {
                pictureSbf.deleteCharAt(0);
            }
            notice.setPictures(pictureSbf.toString());
            File[] files = new File(getNoticeDir(notice.getId())).listFiles();
            if (files != null) {
                for (File file : new File(getNoticeDir(notice.getId())).listFiles()) {//删除需要删除的文件
                    if (!pictureSbf.toString().contains(file.getName())) {
                        file.delete();
                    }
                }
            }
        }
        //数据库保存相关信息
        if (oldNotice == null) {
            notice.setCreator(LoginUtil.getLoginUserId());
            notice.setCreateTime(new Date());
            this.insertSelective(notice);
        } else {
            notice.setModifier(LoginUtil.getLoginUserId());
            notice.setModifyTime(new Date());
            this.updateByPrimaryKeySelective(notice);
        }
        return Result.newSuccessInstance("提交成功");
    }

    /**
     * 获取公告图片文件夹路径
     */
    private String getNoticeDir(String noticeId) {
        return parsePath(picturePath) + File.separator + noticeId + File.separator;
    }

    /**
     * 获取公告图片临时文件夹路径
     */
    private String getNoticeTempDir(String noticeId) {
        return getNoticeTempDir() + noticeId + File.separator;
    }

    /**
     * 获取公告图片临时文件夹路径
     */
    private String getNoticeTempDir() {
        return parsePath(pictureTempPath) + File.separator + LoginUtil.getLoginAccount() + File.separator;
    }

    /**
     * 删除图片
     *
     * @param noticeId    公告id
     * @param pictureName 图片名
     */
    @Override
    public Result deletePicture(String noticeId, String pictureName) {
        boolean result = FileUtils.deleteQuietly(new File(getNoticeTempDir(noticeId) + pictureName));
        if (result) {
            return Result.newSuccessInstance("已成功删除");
        }
        return Result.newFailInstance("未能成功删除");
    }
}

